home *** CD-ROM | disk | FTP | other *** search
- ;==========================================================================;
- ; Interrupt service for 8530 ;
- ; ;
- ; Copyright 1986, 1987, 1988 by H. Roy Engehausen. All rights reserved. ;
- ; This software may be freely distributed and used, but it may not ;
- ; under any circumstances be sold by anyone other than the author. ;
- ; It may be distributed by a commercial company as long as it is ;
- ; for no cost. ;
- ; ;
- ; Permission is explicity granted to use this code as a model for ;
- ; other programs requiring interrupt driven serial I/O as long as they ;
- ; carry this copyright notice and the imbedded constants ;
- ; ;
- ; Here we discover what woke us up ;
- ; Inputs: DX = port address ;
- ; SI = suspected COM block ;
- ;==========================================================================;
-
- ; AX, CX, DX, DI, SI already saved!
- ; CS is ok. DS is not!
-
- scc_more: ; This label used when an interrupt
- ; is serviced but there is more pending
- ; Only SI and DX need be set.
-
- ;--------------------------------------------------------------------------;
- ; What caused this 8530 interrupt. Remember there are two com ports ;
- ; involved. We must always check on channel "B" ;
- ;--------------------------------------------------------------------------;
-
- AND DX,scc_card_mask ; Convert to address of card
- MOV DI,sccb_ctl ; Port address of channel B control
- ADD DX,DI ; Add card base to obtain real address
-
- MOV AL,sccreg2 ; Select reg 2
- OUT DX,AL ; Send it
- IN AL,DX ; Read the thing
-
-
- JMP debug1 ; This is debugging code left in
- ADD AL,48 ; so we can test things by patching the
- CALL dispchar ; JMP to a NOP
- SUB AL,48 ;
- debug1:
-
- ;--------------------------------------------------------------------------;
- ; AL now contains the interrupt vector. First thing is to get SI ;
- ; pointing in the right direction. ;
- ;--------------------------------------------------------------------------;
-
- TEST AL,scc_int_mask ; Is this interrupt on channel "A"
- JZ scc_int_b ; Nope...
- TEST BYTE PTR baseaddr[SI],scc_chan_mask ; Channel "A"?
- JNZ scc_int_do ; Yes... It all matches
- MOV SI,chip_comm[SI] ; Get common chip data area
- MOV SI,DS:0[SI] ; Get Channel "A" pointer
- JMP scc_int_do ; Go handle interrupt
-
- scc_int_b:
-
- TEST BYTE PTR baseaddr[SI],scc_chan_mask ; Channel "B"?
- JZ scc_int_do ; Yes... It all matches
- MOV SI,chip_comm[SI] ; Get common chip data area
- MOV SI,DS:2[SI] ; Get Channel "B" pointer
-
- scc_int_do: ;
-
- ;--------------------------------------------------------------------------;
- ; SI points to the com block of the interrupting channel. Go to the ;
- ; routine we need! ;
- ;--------------------------------------------------------------------------;
-
- MOV DX,baseaddr[SI] ; Get port address
-
- AND AL,0FFH-scc_int_mask ; Remove channel indicator!
- CBW ; Clear top of register
- MOV DI,AX ; Put in valid register
- JMP DS:scc_table[DI] ; Go to it
-
- ; Branches to proper handler. DI = interrupt type, SI = com block,
- ; DX = Control port address for this channel
-
- scc_table LABEL WORD
- DW OFFSET scc_tbe ; 0 = Transmit buffer empty
- DW OFFSET scc_ext ; 2 = External change
- DW OFFSET scc_rda ; 4 = Receive data available
- DW OFFSET scc_src ; 6 = Special receive condition
-
- ;==========================================================================;
- ; Transmit buffer empty ;
- ;==========================================================================;
-
- scc_tbe:
-
- PUSH ES ; Use ES for stuff
- MOV ES,buffer_t_a[SI] ; ES = transmit buffer segement
-
- MOV DI,buffer_t_out[SI] ; Get current buffer position
-
- scc_tbe_loop:
-
- INC DI ; Bump to next
- CMP DI,ES:buffer_dl ; End of packet?
- JAE scc_tbe_done ; Yes.. Must allow underrun to occur
-
- ;--------------------------------------------------------------------------;
- ; Buffer not empty yet so send a character. ;
- ;--------------------------------------------------------------------------;
-
- MOV buffer_t_out[SI],DI ; Save new current buffer position
- MOV AL,ES:[DI] ; Get character to send
-
- OR DL,scc_data_mask ; Convert control port to data port address
- OUT DX,AL ; Send the character
-
- AND DL,0FFH-scc_data_mask ; Port address back
-
- IN AL,DX ; Get the status
- TEST AL,tx_tbe ; Still hungry?
- JNZ scc_tbe_loop ; Yep.. Try again
-
- JMP scc_tbe_exit ; Exit
-
- ;--------------------------------------------------------------------------;
- ; Buffer is empty. End the packet ;
- ;--------------------------------------------------------------------------;
-
- scc_tbe_done: ;
-
- OR flags[SI],flags_tbe ; Signal buffer done
-
- MOV AX,ES:buffer_next ; Next guy in the chain please
- MOV buffer_t_a[SI],AX ;
-
- MOV ES:buffer_next,0 ; Clear the link to prevent loops
-
- OR ES:buffer_st1,buffer_st1_xmt ; Turn on transmitted bit
-
- TEST ES:buffer_st1,buffer_st1_ddb ; Ok to free buffer?
- JNZ scc_tbe_no_free ; Nope
-
- MOV AX,ES ; Free buffer thats in ES
- CALL free_a_buffer ; Let the old buffer go!
-
- scc_tbe_no_free:
-
- OR flags[SI],flags_tbe ; Signal to expect eom
-
- MOV period_xmtr[SI],period_x_crc ; Event = CRC delay
- MOV timer_xmtr[SI],0 ; Set transmitter timer to zero
-
- CALL int_8530 ; Change interrupt service
-
- ;--------------------------------------------------------------------------;
- ; Common TBE exit routine ;
- ;--------------------------------------------------------------------------;
-
- scc_tbe_exit:
-
- POP ES ; Done with ES
-
- MOV AL,rst_txip ; Reset transmitter interrupt pending
- OUT DX,AL ; Put out
-
- JMP scc_exit ; Leave!
-
- ;==========================================================================;
- ; External interrupt ;
- ;==========================================================================;
-
- scc_ext:
-
- IN AL,DX ; Read Register 0 (needs no write)
- MOV last_rs[SI],AL ; Save the status
- MOV AH,AL ; also in a register for later
-
- ;--------------------------------------------------------------------------;
- ; Issue the external interrupt reset command ;
- ;--------------------------------------------------------------------------;
-
- MOV AL,rst_ext ; Issue Reset Ext Interrupt command
- OUT DX,AL ; WR0 needs no prep
-
- ;--------------------------------------------------------------------------;
- ; Is there a TX underrun/eom ? ;
- ;--------------------------------------------------------------------------;
-
- CMP period_xmtr[SI],period_x_tx ; Event = sending data
- JNE scc_ext_no_tx ; Nope.. Ignore this bit
-
- TEST AH,tx_unrun ; Under run?
- JZ scc_ext_no_tx ; Nope...
-
- ; Handle underrun by turning off the transmitter and hoping nothing happens!
-
- AND flags[SI],0FFH-flags_tbe ; Signal to expect eom?
- MOV period_xmtr[SI],period_x_crc ; Event = CRC delay
- MOV timer_xmtr[SI],0 ; Set transmitter timer to zero
-
- MOV AL,sccreg5 ; WR5
- OUT DX,AL ;
- MOV AL,dtr_pin+tx_8bits+rts_pin+tx_crcen+tx_enabl;
- OUT DX,AL ;
-
- scc_ext_no_tx: ;
-
- ;--------------------------------------------------------------------------;
- ; If we have a break or abort, empty the receiver buffer. ;
- ;--------------------------------------------------------------------------;
-
- TEST AH,rx_abort ; Abort?
- JZ scc_ext_no_abort ; Nope
-
- scc_ext_abort_rda: ;
-
- OR DL,scc_data_mask ; Get the data port address
- IN AL,DX ; Grab the character
- AND DL,0FFH-scc_data_mask ; Convert back to control address
-
- IN AL,DX ; Get the latest status
-
- TEST AL,rx_abort ; Abort?
- JZ scc_ext_no_abort ; Nope
- TEST AL,rx_rda ; RDA still?
- JNZ scc_ext_abort_rda ; Yep.. Try again
-
- MOV buffer_r_in[SI],0 ; Zero the count in the buffer
-
- scc_ext_no_abort: ;
-
- ;--------------------------------------------------------------------------;
- ; Special routines for DCD on or off ;
- ;--------------------------------------------------------------------------;
-
- TEST AH,dcd_pin ; DCD on?
- JNZ scc_ext_dcd_on ; Yep...
-
- ;--------------------------------------------------------------------------;
- ; If DCD dropped then end the packet and reset the receiver ;
- ;--------------------------------------------------------------------------;
-
- TEST flags[SI],flags_dcd_on ; Was DCD on previously?
- JZ scc_ext_dcd_off ; Nope...
-
- AND flags[SI],0FFH-flags_dcd_on ; Show DCD was off
-
- CALL ron_8530 ; Initialize the receiver
-
- MOV buffer_r_in[SI],0 ; Zero the count in the buffer
-
- scc_ext_dcd_off:
-
- JMP scc_exit ; Leave!
-
- ;--------------------------------------------------------------------------;
- ; If DCD just came on then ready the receiver ;
- ;--------------------------------------------------------------------------;
-
- scc_ext_dcd_on: ;
-
- TEST flags[SI],flags_dcd_on ; Was DCD on previously?
- JNZ scc_ext_dcd_ok ; Yep...
-
- OR flags[SI],flags_dcd_on ; Show DCD was on
-
- CALL ron_8530 ; Initialize the receiver
-
- MOV buffer_r_in[SI],0 ; Zero the count in the buffer
-
- scc_ext_dcd_ok: ;
-
- JMP scc_exit ; Leave!
-
- ;==========================================================================;
- ; Receive Data Available ;
- ;==========================================================================;
-
- scc_rda:
-
- OR DL,scc_data_mask ; Get the data port address
- IN AL,DX ; Grab the character
- AND DL,0FFH-scc_data_mask ; Convert back to control address
-
- ;--------------------------------------------------------------------------;
- ; Put the character away. If no room, we will simulate an overrun! ;
- ;--------------------------------------------------------------------------;
-
- MOV DI,buffer_r_in[SI] ; Where does it go?
- CMP DI,buffer_siz2 ; but first, is there room?
- JAE scc_rda_overrun ; No room......
-
- PUSH ES ; We will need ES
- MOV ES,buffer_r_a[SI] ; Get buffer address
- MOV ES:[DI],AL ; Stuff character in buffer
- POP ES ; Done with ES
-
- INC DI ; Bump counter
- MOV buffer_r_in[SI],DI ; And save it
-
- scc_rda_overrun: ; Until we figure out something better
-
- ;--------------------------------------------------------------------------;
- ; If there is more receive data, process it ;
- ;--------------------------------------------------------------------------;
-
- IN AL,DX ; RR0 (No select needed)
-
- TEST AL,rx_rda ; Any more data?
- JNZ scc_rda ; Yes.. try again
-
- MOV last_rs[SI],AL ; Save the status
-
- JMP scc_exit ; All done
-
- ;==========================================================================;
- ; Special Receive Condition ;
- ;==========================================================================;
-
- scc_src:
-
- PUSH ES ; Gonna need ES for
- MOV ES,buffer_r_a[SI] ; pointing to the receive buffer
-
- ;--------------------------------------------------------------------------;
- ; Empty the receive buffer if anything left ;
- ;--------------------------------------------------------------------------;
-
- MOV DI,buffer_r_in[SI] ; Where does it go?
-
- scc_src_data:
-
- IN AL,DX ; RR0 (no select needed)
-
- TEST AL,rx_rda ; Any more data?
- JZ scc_src_no_data ; Nope
-
- OR DL,scc_data_mask ; Get the data port address
- IN AL,DX ; Grab the character
- AND DL,0FFH-scc_data_mask ; Convert back to control address
-
- CMP DI,buffer_siz2 ; Room in buffer?
- JAE scc_src_overrun ; No room......
-
- MOV ES:[DI],AL ; Stuff character in buffer
- INC DI ; Bump counter
-
- scc_src_overrun:
- JMP scc_src_data
-
- scc_src_no_data:
-
- ;--------------------------------------------------------------------------;
- ; Save the status bytes becuz this is packet end one way or another ;
- ;--------------------------------------------------------------------------;
-
- MOV ES:buffer_st1,AL ; Save this as first status byte
-
- MOV ES:buffer_dl,DI ; Save the data length
-
- MOV AL,sccreg1 ; We want R1
- OUT DX,AL ; so select it then
- IN AL,DX ; read it!
-
- MOV ES:buffer_st2,AL ; Save this as second status byte
-
- ;--------------------------------------------------------------------------;
- ; Reset receive CRC if necessary ;
- ;--------------------------------------------------------------------------;
-
- TEST AL,rx_eof+rx_crcerr+rx_ovrn ;
- JZ scc_src_no_crc ;
-
- MOV AL,rst_rcrc ; Reset RX CRC checker
- OUT DX,AL
-
- scc_src_no_crc: ;
-
- ;--------------------------------------------------------------------------;
- ; If packet in error and user don't want it then throw away. ;
- ; Actually we will reuse the darn thing ;
- ;--------------------------------------------------------------------------;
-
- TEST options[SI],opt_igerr ; Ignore error?
- JNZ scc_src_noig ; Nope...
- TEST ES:buffer_st2,rx_crcerr+rx_ovrn ; Error?
- JNZ scc_src_ignore ; Nope.
- TEST ES:buffer_st1,rx_abort ; Abort
- JNZ scc_src_ignore ; Nope.
-
- scc_src_noig:
-
- ;--------------------------------------------------------------------------;
- ; Save the packet and prepare for next one ;
- ;--------------------------------------------------------------------------;
-
- MOV DI,ES ; Save current buffer address
-
- CALL get_a_buffer ; Get the new buffer for the chain
- OR AX,AX ; Did we find one?
- JZ scc_src_no_buff ; Nope... Forget it
- MOV ES,AX ; Address the new buffer
-
- MOV ES:buffer_next,DI ; Chain with most recent (the new one)
- MOV buffer_r_a[SI],ES ; on the head
-
- ;--------------------------------------------------------------------------;
- ; Read for next packet! ;
- ;--------------------------------------------------------------------------;
-
- scc_src_ignore: ; Come here when ignoring a packet in error
-
- SUB AX,AX ; Zero the count of bytes in the
- MOV buffer_r_in[SI],AX ; receive buffer
-
- scc_src_no_buff: ; No buffers available
-
- POP ES ; All done with ES for now
-
- ;--------------------------------------------------------------------------;
- ; Reset Register 1 status ;
- ;--------------------------------------------------------------------------;
-
- MOV AL,rst_err1 ; Reset errors
- OUT DX,AL ; Send it out
-
- ;--------------------------------------------------------------------------;
- ; All done with this one ;
- ;--------------------------------------------------------------------------;
-
- ;fallthru JMP scc_exit ; All done
-
- ;==========================================================================;
- ; Interrupt exit! ;
- ;==========================================================================;
-
- scc_exit:
-
- ;--------------------------------------------------------------------------;
- ; Tell 8530 we are all done ;
- ;--------------------------------------------------------------------------;
-
- MOV DX,baseaddr[SI] ; Get port address
- MOV AL,rst_ius ; Reset highest interrupt under service
- OUT DX,AL
-
- ;--------------------------------------------------------------------------;
- ; Tell the 8259 we are done ;
- ;--------------------------------------------------------------------------;
-
- MOV AL,pic_clear ; Tell 8259 we are done
-
- TEST options[SI],opt_high_irq ; Slave 8259 involved?
- JZ scc_pic_master ; Nope
-
- OUT pic2_cmd_port,AL ; Clear slave
-
- scc_pic_master:
-
- OUT pic_cmd_port,AL ; Clear master
-
- ;--------------------------------------------------------------------------;
- ; See if anything left for this chip? ;
- ;--------------------------------------------------------------------------;
-
- OR DL,scc_chan_mask ; Force us to channel "A"
- MOV AL,sccreg3 ; RR3 please
- OUT DX,AL ;
- IN AL,DX ;
-
- OR AL,AL ; Anything pending?
- JZ scc_ok_to_go ; Nope.. Leave
-
- MOV DX,baseaddr[SI] ; Get port address
- JMP scc_more ; Go service the interrupts
-
- scc_ok_to_go: ; Ok to exit
-
- ;--------------------------------------------------------------------------;
- ; Leave ;
- ;--------------------------------------------------------------------------;
-
- JMP serint_exit ; Go to common exit routine